﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.ComponentModel;

namespace EasyFFmpeg.FFmpeg
{
    /// <summary>
    /// Wrapper class for running FFMPEG.
    /// </summary>
    public class FFmpegWrapper
    {
        public event EventHandler<DataReceivedEventArgs> OutputReceived;
        public event EventHandler<EventArgs> ConversionCompleted;

        public FFmpegWrapper(string sourceFile, string targetFile)
        {
            this.SourceFile = sourceFile;
            this.TargetFile = targetFile;
            this.AudioOptions = new AudioOptions();
            this.VideoOptions = new VideoOptions();
        }

        #region Properties

        /// <summary>
        /// The path to the source file.
        /// </summary>
        public string SourceFile { get; set; }

        /// <summary>
        /// The output file name.
        /// </summary>
        public string TargetFile { get; set; }

        /// <summary>
        /// Gets the audio options applied to the wrapper.
        /// </summary>
        public AudioOptions AudioOptions { get; private set; }

        /// <summary>
        /// Gets or sets the video options.
        /// </summary>
        public VideoOptions VideoOptions { get; set; }


        #endregion

        #region Methods

        /// <summary>
        /// Gets the arguments to be used when converting.
        /// </summary>
        private string BuildArguments()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(" -i \"").Append(this.SourceFile).Append("\"");
            sb.Append(" -sameq");   // maintain quality
            sb.Append(" -y");       // overwrite files

            // add video options
            if (this.VideoOptions.Deinterlace)
            {
                sb.Append(" -filter:v yadif");
            }

            // add audio options
            if (!String.IsNullOrEmpty(this.AudioOptions.Channels))
            {
                sb.Append(" -ac ").Append(this.AudioOptions.Channels);
            }

            sb.Append(" \"").Append(this.TargetFile).Append("\"");
            return sb.ToString();
        }

        /// <summary>
        /// Kicks off the file conversion process.
        /// </summary>
        public void Convert()
        {
            Thread t = new Thread(new ThreadStart(ConvertWorker));
            t.Start();
        }

        private void ConvertWorker()
        {
            using (Process proc = new Process())
            {
                proc.StartInfo = new ProcessStartInfo()
                {
                    Arguments = this.BuildArguments(),
                    CreateNoWindow = true,
                    FileName = "\"" + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ffmpeg.exe") + "\"",
                    RedirectStandardError = true,
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                };
                proc.EnableRaisingEvents = true;
                proc.Start();

                proc.OutputDataReceived += new DataReceivedEventHandler(OnOutputReceived);
                proc.BeginOutputReadLine();
                proc.ErrorDataReceived += new DataReceivedEventHandler(OnOutputReceived);
                proc.BeginErrorReadLine();
                proc.Exited += new EventHandler(OnProcessExited);

                proc.WaitForExit();
                proc.Close();
            }
            
        }

        #endregion

        #region Event Handlers

        protected void OnOutputReceived(object sender, DataReceivedEventArgs e)
        {
            if (this.OutputReceived != null)
            {
                this.OutputReceived(this, e);
            }
        }

        void OnProcessExited(object sender, EventArgs e)
        {
            if (this.ConversionCompleted != null)
            {
                this.ConversionCompleted(this, new EventArgs());
            }
        }

        #endregion
    }
}
